﻿using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Net.Mail;
using System.Threading;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Xml.Linq;

namespace NoteBox
{
    public class Message
    {
        public int number;
        public int size;
        public string receivedfrom;
        public string receivedby;
        public string from;
        public string to;
        public string date;
        public string uidl;
        //
        public string contentType;
        public string boundary;
        public string status;
        public string MessageID;
        //
        public string subject;
        //
        public string message;

    }
    public class PostBox
    {
        private int numberOfMessages;
        private int sizeOfMessages;
        public string tempErrorString;
        public int tempMessageSize;
        //
        public bool StoppedFromAnOtherProcess = false;
        public List<string> tempMessageStrings = new List<string>();
        //
        /// <summary>
        /// Количество сообщений в ящике
        /// </summary>
        public int NumberOfMessages
        {
            get
            {
                return numberOfMessages;
            }
        }
        /// <summary>
        /// Размер всех сообщений в почтовом ящике
        /// </summary>
        public int SizeOfMessages
        {
            get
            {
                return sizeOfMessages;
            }
        }

        public PostBox(int numbofmess, int sizeofmess)
        {
            numberOfMessages = numbofmess;
            sizeOfMessages = sizeofmess;
        }
    }


    public class pop3
    {
        public event dResp ResponceAdded;
        public enum eMessageType { Sended, Received }
        public enum eEncodingType { KOI8R, ANSI, Windows1251, Unicode, utf32 };

        #region !!!!!!!!!!!!!!gavno!!!!!!!!!
        /*
        public MailHeader GetMail(int num, bool body)
        {
            MailHeader mailHeader = null;
            try
            {
                string sTemp=null;
                if (body == true)
                {
                    //retr(num);
                    sTemp = responseString(0);
                }
                //else
                    //sTemp = SendCommand("TOP " + num + "\r\n");

                if (sTemp.StartsWith("+OK"))
                {
                    string[] param = sTemp.Split(' ');

                    string delimiter = "--";
                    mailHeader = new MailHeader();
                    mailHeader.number = num;
                    mailHeader.size = int.Parse(param[1]);

                    StringBuilder sBody = new StringBuilder();

                    for (int i=1; i<responseLength(); i++)
                    {
                        sTemp = responseString(i);
                        //MessageBox.Show(sTemp);
                        if (sTemp == ".")
                        {
                            SetMailHeader(mailHeader, sBody.ToString());
                            break;
                        }
                        else if (sTemp.Length > 0 && sTemp[0] <= ' ')
                        {
                            sBody.Append(sTemp);
                        }
                        // Begin off message body
                        else if (sTemp.StartsWith(delimiter))
                        {
                            // new Message
                            ReadMessage(mailHeader);
                        }
                        else
                        {
                            if (sBody.Length > 0)
                            {
                                SetMailHeader(mailHeader, sBody.ToString());
                                delimiter = "--" + mailHeader.boundary;
                            }

                            sBody = new StringBuilder(sTemp);
                        }
                    }
                    // . - is the end of the server response
                }
            }
            catch (Exception)
            {
                return null;
            }
            return mailHeader;
        }



        bool ReadMessage(MailHeader mailHeader)
        {
            if (mailHeader.messages == null)
            {
                mailHeader.messages = new ArrayList();
            }

            MailMessage mailMessage = new MailMessage();
            string delimiter = "--" + mailHeader.boundary;

            StringBuilder sBody = new StringBuilder();

            string sTemp = responseString(0);

            sBody.Append(sTemp);
            bool readHeder = true;
            for (int i=1; i<responseLength(); i++)
            {
                sTemp = responseString(i);
                if (readHeder)
                {
                    if (sTemp.Length > 0 && sTemp[0] <= ' ')
                    {
                        sBody.Append(sTemp);
                        continue;
                    }

                    string key = sBody.ToString();
                    sBody.Length = 0;
                    if (sTemp.Length == 0)
                    {
                        readHeder = false;
                    }
                    else
                    {
                        sBody.Append(sTemp);
                    }

                    if (key.StartsWith("Content-Type: "))
                    {
                        mailMessage.contentType = key.Remove(0, 14);
                    }
                    else if (key.StartsWith("Content-Transfer-Encoding: "))
                    {
                        mailMessage.contentTransferEncoding = key.Remove(0, 27);
                    }
                }
                else if (sTemp.StartsWith(delimiter))
                {
                    mailMessage.message = sBody.ToString();
                    mailHeader.messages.Add(mailMessage);

                    if (sTemp.Remove(0, delimiter.Length) == "--")
                    {
                        return true;
                    }

                    mailMessage = new MailMessage();
                    sBody.Length = 0;
                    sBody.Append(responseString(++i));
                    readHeder = true;
                }
                else
                {
                    sBody.Append(sTemp);
                    sBody.Append("\r\n");
                }
            }
            return false;
        }
        */
        #endregion

        private bool useSSL = true;
        private int port;
        private string host;
        private string userName;
        private string password;
        private TcpClient client;
        private SslStream sslstream;
        private NetworkStream netstream;
        public PostBox MyPostBox;
        public Message MyTempMessage;

        #region Конструкторы
        /// <summary>
        /// Iniatilize a new instance of pop3SSL.pop3C using the host name and port supplied and create a new response list
        /// </summary>
        /// <param name="host">Host name to connect ex: pop.gmail.com</param>
        /// <param name="port">Port to connect to ex:995</param>
        public pop3(string host, int port, bool ssl)
        {
            userName = null;
            password = null;
            this.host = host;
            this.port = port;
            this.useSSL = ssl;
            MyPostBox = new PostBox(0, 0);
            MyTempMessage = new Message();
        }
        #endregion

        #region Установка полей (свойства)
        /// <summary>
        /// Gets or sets the port to connect
        /// </summary>
        public int Port
        {
            get
            {
                return port;
            }
            set
            {
                port = value;
            }
        }

        /// <summary>
        /// Gets or sets the host to connect 
        /// </summary>
        public string Host
        {
            get
            {
                return host;
            }

            set
            {
                host = value;
            }
        }

        /// <summary>
        /// Gets or sets the username to use for login
        /// </summary>
        public string UserName
        {
            get
            {
                return userName;
            }

            set
            {
                userName = value;
            }
        }

        /// <summary>
        /// Gets or sets the password to use for login
        /// </summary>
        public string Password
        {
            get
            {
                return password;
            }

            set
            {
                password = value;
            }
        }
        #endregion

        #region certificate methods
        /// <summary>
        /// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication
        /// </summary>
        /// <param name="sender">An object that contains state information for this validation</param>
        /// <param name="certificate">The certificate used to authenticate the remote party</param>
        /// <param name="chain">The chain of certificate authorities associated with the remote certificate</param>
        /// <param name="sslPolicyErrors">One or more errors associated with the remote certificate</param>
        /// <returns>A System.Boolean value that determines whether the specified certificate is accepted for authentication</returns>
        private bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None)
                return true;

            Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
            return false;
        }

        /// <summary>
        /// Selects the local Secure Sockets Layer (SSL) certificate used for authentication
        /// </summary>
        /// <param name="sender">An object that contains state information for this validation</param>
        /// <param name="targetHost">The host server specified by the client</param>
        /// <param name="localCertificates">An System.Security.Cryptography.X509Certificates.X509CertificateCollection containing local certificates</param>
        /// <param name="remoteCertificate">The certificate used to authenticate the remote party</param>
        /// <param name="acceptableIssuers">A System.String array of certificate issuers acceptable to the remote party</param>
        /// <returns>An System.Security.Cryptography.X509Certificates.X509Certificate used for establishing an SSL connection</returns>
        private X509Certificate SelectLocalCertificate(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
        {
            if (acceptableIssuers != null && acceptableIssuers.Length > 0 && localCertificates != null && localCertificates.Count > 0)
            {
                foreach (X509Certificate certificate in localCertificates)
                {
                    string issuer = certificate.Issuer;
                    if (Array.IndexOf(acceptableIssuers, issuer) != -1)
                        return certificate;
                }
            }

            if (localCertificates != null && localCertificates.Count > 0)
                return localCertificates[0];
            return null;
        }
        #endregion

        #region SetConnect и login методы

        public bool SetConnect(string _username, string _pass)
        {
            if (!login(_username, _pass))
                return false;
            // теперь подсоеденились... заполним структуру почтового ящика.
            try
            {
                stat();
            }
            catch (Exception ex)
            {
                ResponceAdded("Ошибка (SetConnect(stat)):" + ex.ToString());
                return false;
            }
            return true;
        }
        
        //////////////////////////////////////////
        /// <summary>
        /// Login to the pop3 host on the specified port
        /// </summary>
        /// <param name="userName">The username to use for login</param>
        /// <param name="password">The password to use for login</param>
        /// <returns>True if successful else false</returns>
        private bool login(string userName, string password)
        {
            int res;
            string answer;
            byte[] bytes;
            if (host == null || port == 0 || userName == null || password == null)
            {
                return false;
            }
            try
            {
                client = new TcpClient(host, port);
                bytes = new byte[1024];
                if (useSSL)
                {
                    sslstream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), new LocalCertificateSelectionCallback(SelectLocalCertificate));
                    sslstream.AuthenticateAsClient(host);
                    res = sslstream.Read(bytes, 0, bytes.Length);
                }
                else
                {
                    netstream = client.GetStream();
                    res = netstream.Read(bytes, 0, bytes.Length);
                } 
                answer = Encoding.ASCII.GetString(bytes, 0, res);
                if (!answer.StartsWith("+OK"))
                {
                    ResponceAdded("Ошибка: нету подключения к серверу");
                    return false;
                }
                /// имя пользователя
                answer = SendCommand("USER " + userName + "\r\n");
                if (!answer.StartsWith("+OK"))
                {
                    ResponceAdded("Ошибка: Отсутствует пользователь "+userName);
                    return false;
                }
                /// пароль
                answer = SendCommand("PASS " + password + "\r\n");
                if (!answer.StartsWith("+OK"))
                {
                    ResponceAdded("Ошибка: пользователь " + userName +". Неверный пароль!");
                }
            }
            catch (Exception ex)
            {
                ResponceAdded("Ошибка (pop.login):"+ex.ToString());
                return false;
            }

            return true;
        }
        /////////////////////////////////////////        
        #endregion

        string SendCommand(string command)
        {
            int res;
            string answer="";
            byte[] bytes = new byte[1024];
            if (useSSL)
            {
                sslstream.Write(Encoding.ASCII.GetBytes(command));
                res = sslstream.Read(bytes, 0, bytes.Length);
            }
            else
            {
                //byte[] bData = System.Text.Encoding.ASCII.GetBytes((command).ToCharArray());
                netstream.Write(Encoding.ASCII.GetBytes(command), 0, Encoding.ASCII.GetBytes(command).Length);
                //netstream.Write(bData, 0, bData.Length);
                res = netstream.Read(bytes, 0, bytes.Length);
            }
            answer = Encoding.ASCII.GetString(bytes, 0, res);
            return answer;
        }

        #region Endconnect method //
        /// <summary>
        /// Logout from the session
        /// </summary>
        /// <returns>True if successful else false</returns>
        public bool EndConnect()
        {
            string answer;
            try
            {
                answer = SendCommand("QUIT \r\n");
                if (!answer.StartsWith("+OK"))
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                ResponceAdded("Ошибка (endconnect): "+ex.ToString());
                return false;
            }
            return true;
        }
        #endregion

        #region stat method // default + create MyPostBox
        /// <summary>
        /// Send the STAT command to know statistics of the mailbox
        /// </summary>
        /// <returns>True if successful else false. If successful, sets the numMessages and sizeOctet field
        /// to the number of number of messages in the inbox and total size in octets</returns>
        private bool stat()
        {
            char[] separator = new char[1];
            separator[0] = ' ';
            try
            {
                string str = SendCommand("STAT \r\n");
                if (!str.StartsWith("+OK"))
                {
                    return false;
                }
                int numMessages = int.Parse(str.ToString().Split(separator)[1]);
                int sizeOctet = int.Parse(str.ToString().Split(separator)[2]);
                //
                MyPostBox = new PostBox(numMessages, sizeOctet);
            }
            catch (Exception ex)
            {
                ResponceAdded("Ошибка: (stat): " + ex.Message.ToString());
                return false;
            }
            return true;
        }
        #endregion

        #region ReceiveMessage method
        /// <summary>
        /// Send the RETR nn command
        /// </summary>
        /// <param name="nn">The message number to retrieve</param>
        /// <returns>True if successful else false</returns>
        public Message ReceiveMessage(int nn)
        {
            MyPostBox.StoppedFromAnOtherProcess = false;
            ResponceAdded("Всего сообщений: " + MyPostBox.NumberOfMessages.ToString() + ";   Прием сообщения: " + nn.ToString());
            StreamReader sr; 
            if (useSSL)
                sr = new StreamReader(sslstream, Encoding.Default);
            else
                sr = new StreamReader(netstream, Encoding.Default);
            string str;
            int i = 0;
            try
            {
                // message size
                if (MyPostBox.StoppedFromAnOtherProcess)
                    return null;
                str = SendCommand("LIST " + nn.ToString() + "\r\n");
                if (!str.StartsWith("+OK"))
                    return null;
                MyPostBox.tempMessageSize = int.Parse(str.ToString().Split(' ')[2]);
                // uidl
                str = SendCommand("UIDL " + nn.ToString() + "\r\n");
                if (!str.StartsWith("+OK"))
                    return null;
                str = str.Replace("\r\n","");
                MyTempMessage.uidl = str.Substring(str.LastIndexOf(" ")+1);
                //
                if (useSSL)
                    sslstream.Write(Encoding.ASCII.GetBytes("RETR " + nn.ToString() + "\r\n"));
                else
                {
                    byte[] bData = System.Text.Encoding.ASCII.GetBytes(("RETR " + nn.ToString() + "\r\n").ToCharArray());
                    netstream.Write(bData, 0, bData.Length);
                }
                MyPostBox.tempMessageStrings.Clear();
                int jot = 0;
                while (true)
                {
                    i++;
                    str = sr.ReadLine();
                    MyPostBox.tempMessageStrings.Add(str);
                    
                    if (i % 500 == 0)
                    {
                        string hstr = "Всего сообщений: " + MyPostBox.NumberOfMessages.ToString() + ";   Прием сообщения: " + nn.ToString()+" ";
                        jot++; if (jot > 20) jot = 0;
                        for (int k = 0; k < jot; k++)
                            hstr += ">";
                        ResponceAdded(hstr);
                    }
                    if (str == ".")
                    {
                        break;
                    }

                }
            }
            catch (Exception ex)
            {
                MyPostBox.tempErrorString = "Ошибка: (pop_ReceiveMessage): " + ex.ToString();
                ResponceAdded(MyPostBox.tempErrorString);
                return null;
            }
            Message mess = ParseMessage(nn);
            if (mess == null) // там же отпарсеное отправляется в таблицу
                return null;
            return mess;
        }
        #endregion

        #region StartMessageRecognition method
        /// <summary>
        /// Send the RETR nn command
        /// </summary>
        /// <param name="nn">The message number to retrieve</param>
        /// <returns>True if successful else false</returns>
        public int StartMessageRecognition(string logFileName)
        {
            
            if (!File.Exists(logFileName))
                return 1;  // в общем случае 1 ретерним даже если ошибка, или если нету принятых сообщений
            // Грузим из лога
            List<string> UIDLLog = new List<string>();
            XDocument XDoc = XDocument.Load(logFileName);
            foreach (XElement xel in XDoc.Element("MailList").Elements())
                UIDLLog.Add((string)xel.Element("UIDL"));
            // Загрузили // теперь из почты
            StreamReader sr;
            List<string> UIDLServer = new List<string>();
            if (useSSL)
            {
                sr = new StreamReader(sslstream, Encoding.Default);
                sslstream.Write(Encoding.ASCII.GetBytes("UIDL \r\n"));
            }
            else
            {
                sr = new StreamReader(netstream, Encoding.Default);
                byte[] bData = System.Text.Encoding.ASCII.GetBytes(("UIDL \r\n").ToCharArray());
                netstream.Write(bData, 0, bData.Length);
            }
            string str = sr.ReadLine();
            if (!str.StartsWith("+OK"))
                return 1;
            while (true)
            {
                str = sr.ReadLine();
                if (str == ".")
                    break;
                UIDLServer.Add(str.Split(' ')[1]);
            }
            // теперь сравниваем.
            if (UIDLServer.Count > 0)
            {
                if (UIDLLog.IndexOf(UIDLServer[0]) == -1)
                    return 1;
                // теперь идем с конца сервера.
                for (int i = UIDLServer.Count - 1; i >= 0; i--)
                {
                    if (UIDLLog.IndexOf(UIDLServer[i]) != -1)
                        return i + 2;
                }
            }
            return 1;
        }

        #endregion
        
        #region delete method
        /// <summary>
        /// Send the DELE nn command
        /// </summary>
        /// <param name="nn">The message to delete</param>
        /// <returns>True if successful else false</returns>
        public bool dele(int nn)
        {
            byte[] bytes;

            try
            {

                //instream.Write(Encoding.ASCII.GetBytes("DELE " + nn + "\r\n"));
                bytes = new byte[1024];
                //res = instream.Read(bytes, 0, bytes.Length);
                //response.Add(Encoding.ASCII.GetString(bytes, 0, res));
                //if (response[response.Count - 1].ToString().StartsWith("+OK") == false)
                {
                   // return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception occurred: {0}", ex.ToString());
                return false;
            }
            return true;
        }
        #endregion

        // ParseMessage
        Message ParseMessage(int nn)
        {
            MyTempMessage.number = nn;
            //
            MyTempMessage.receivedfrom = "";
            MyTempMessage.receivedby = "";
            //
            for (int i = 0; i < MyPostBox.tempMessageStrings.Count; i++)
            {
                //
                try
                {
                    int j = 1;
                    while (MyPostBox.tempMessageStrings[i + j].StartsWith("\t"))
                    {
                        MyPostBox.tempMessageStrings[i] += MyPostBox.tempMessageStrings[i + j].Replace("\t", " ");
                        j++;
                        if (j > 5) break;
                    }
                    while (MyPostBox.tempMessageStrings[i + j].StartsWith(" =?"))
                    {
                        MyPostBox.tempMessageStrings[i] += " ";
                        MyPostBox.tempMessageStrings[i] += MyPostBox.tempMessageStrings[i + j];
                        j++;
                        if (j > 5) break;
                    }
                    //
                    ParseLine(MyPostBox.tempMessageStrings[i]);
                    if (MyPostBox.tempMessageStrings[i] == "" || MyPostBox.tempMessageStrings[i].StartsWith("--"))
                        break;
                }
                catch (Exception ex)
                {
                    MyPostBox.tempErrorString = "Ошибка: (pop_ParseMessage): " + ex.ToString();
                    ResponceAdded(MyPostBox.tempErrorString);
                    return null;
                }
            }
            int jkkk = 0;
            jkkk++;
            //
            MyPostBox.tempMessageStrings.Clear();
            //
            MyTempMessage.from = ParseDecoder(MyTempMessage.from,"utf-8","8");
            MyTempMessage.to = ParseDecoder(MyTempMessage.to,"utf-8","8");
            MyTempMessage.subject = ParseDecoder(MyTempMessage.subject, "utf-8", "8");
            MyTempMessage.size = MyPostBox.tempMessageSize;
            
            DateTime dd = new DateTime();
            string strDate = MyTempMessage.date;
            if (MyTempMessage.date.LastIndexOf("(")>0)
                strDate = MyTempMessage.date.Remove(MyTempMessage.date.LastIndexOf("("));
            if (DateTime.TryParse(strDate, out dd))
            {
                MyTempMessage.date = dd.ToShortDateString() + ", " + dd.ToShortTimeString();
            }
            else
            {
                string[] arr1 = new string[] { "янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек" };
                string[] arr2 = new string[] { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sen", "okt", "nov", "dec" };
                for (int lo=0; lo<12; lo++)
                    if (strDate.ToLower().Contains(arr1[lo]))
                        strDate = strDate.ToLower().Replace(arr1[lo],arr2[lo]);
                if (strDate.Contains(","))
                    strDate = strDate.Remove(0, 4);
                strDate = strDate.ToLower().Replace("ut", "");
                strDate = strDate.Trim();
                if (DateTime.TryParse(strDate, out dd))
                    MyTempMessage.date = dd.ToShortDateString() + ", " + dd.ToShortTimeString();
            }
            return MyTempMessage;
        }
        bool ParseLine(string key)
        {
            try
            {
                if (key.ToLower().StartsWith("received: by"))
                {
                    MyTempMessage.receivedby = key.Remove(0, 12);
                }
                else if (key.ToLower().StartsWith("received: from"))
                {
                    MyTempMessage.receivedfrom = key.Remove(0, 14);
                }
                else if (key.ToLower().StartsWith("from: "))
                {
                    MyTempMessage.from = key.Remove(0, 6);
                }
                else if (key.ToLower().StartsWith("to: "))
                {
                    MyTempMessage.to = key.Remove(0, 4);
                }
                else if (key.ToLower().StartsWith("subject: "))
                {
                    MyTempMessage.subject = key.Remove(0, 9);
                }
                else if (key.ToLower().StartsWith("date: "))
                {
                    MyTempMessage.date = key.Remove(0, 6);
                }

                else if (key.ToLower().StartsWith("message-id: "))
                {
                    MyTempMessage.MessageID = key.Remove(0, 12);
                }
                else if (key.ToLower().StartsWith("content-type: "))
                {
                    int index = key.IndexOf("boundary=");
                    MyTempMessage.boundary = "";

                    if (index != -1)
                    {
                        if (key[index + 9] == '\"')
                        {
                            int index2 = key.IndexOf("\"", index + 10);
                            if (index2 != -1)
                                MyTempMessage.boundary = key.Substring(index + 10, index2 - index - 10);
                            else
                                MyTempMessage.boundary = key.Substring(index + 10);
                        }
                        key = key.Substring(0, index);
                    }
                    MyTempMessage.contentType = key.Remove(0, 14);
                }

                else if (key.ToLower().StartsWith("status: "))
                {
                    MyTempMessage.status = key.Remove(0, 8);
                }
                else
                    return false;
            }
            catch (Exception ex)
            {
                MyPostBox.tempErrorString = "Ошибка: (pop_ParseLine): " + ex.ToString();
                ResponceAdded(MyPostBox.tempErrorString);
                return false;
            }
            return true;
        }

        // Получает строку. Выделяет кодировки из нее, Вызывает DecodeLine
        string ParseDecoder(string encstring,string defaultCharset,string defaultEncType)
        {
            List<string> decStrings = new List<string>();
            List<string> decCharsets = new List<string>();
            List<string> decEncodingTypes = new List<string>();
            string FinishString = "";
            //
            while (encstring != "")
            {
                // проверяем на наличие кодирования
                int index = -1;
                if (encstring.Contains("=?"))
                {
                    index = encstring.IndexOf("=?");
                    if (index > 0)
                    {
                        decStrings.Add(encstring.Substring(0, index));
                        decCharsets.Add(defaultCharset);
                        decEncodingTypes.Add(defaultEncType);
                        encstring = encstring.Remove(0, index);
                    }
                    // кодировка с начала строки
                    if (index == 0)
                    {
                        encstring = encstring.Replace("?q?", "?q? ");  // необходимо для корректности q кодировок
                        encstring = encstring.Replace("?Q?", "?Q? ");  //
                        int index2 = encstring.IndexOf("?=");
                        string mtemp = encstring.Substring(0, index2+2);
                        string mcharset = "";
                        string menctype = "";
                        #region выделение кодировки
                        encstring = encstring.Remove(0, index2 + 2);
                        // теперь кодировка
                        if (mtemp.ToLower().Contains("utf-8"))
                            mcharset = mcharset = mtemp.Substring(mtemp.ToLower().IndexOf("utf-8"), 5);
                        else if (mtemp.ToLower().Contains("windows-1251"))
                            mcharset = mtemp.Substring(mtemp.ToLower().IndexOf("windows-1251"), 12);
                        else if (mtemp.ToLower().Contains("koi8-r"))
                            mcharset = mtemp.Substring(mtemp.ToLower().IndexOf("koi8-r"), 6);
                        else if (mtemp.ToLower().Contains("koi8-u"))
                            mcharset = mtemp.Substring(mtemp.ToLower().IndexOf("koi8-u"), 6);
                        else if (mtemp.ToLower().Contains("iso-8859-5"))
                            mcharset = mtemp.Substring(mtemp.ToLower().IndexOf("iso-8859-5"), 10);
                        // тип кодировки
                        if (mtemp.ToLower().Contains("?b?"))
                            menctype = "b";
                        if (mtemp.ToLower().Contains("?q?"))
                            menctype = "q";
                        // все возможные варианты
                        mtemp = mtemp.Replace("=?" + mcharset.ToLower() + "?" + menctype.ToLower() + "?", "");
                        mtemp = mtemp.Replace("=?" + mcharset.ToLower() + "?" + menctype.ToUpper() + "?", "");
                        mtemp = mtemp.Replace("=?" + mcharset.ToUpper() + "?" + menctype.ToLower() + "?", "");
                        mtemp = mtemp.Replace("=?" + mcharset.ToUpper() + "?" + menctype.ToUpper() + "?", "");
                        mtemp = mtemp.Replace("=?" + mcharset + "?" + menctype.ToUpper() + "?", "");
                        mtemp = mtemp.Replace("=?" + mcharset + "?" + menctype.ToUpper() + "?", "");
                        mtemp = mtemp.Replace("?=","");
                        if (mcharset == "iso-8859-5") mcharset = "iso_8859-5";
                        decStrings.Add(mtemp);
                        decCharsets.Add(mcharset);
                        decEncodingTypes.Add(menctype);
                        #endregion
                    }
                }
                else // если кодирования нету
                {
                    decStrings.Add(encstring);
                    decCharsets.Add(defaultCharset);
                    decEncodingTypes.Add(defaultEncType);
                    encstring = "";
                }
                encstring = encstring.Replace(" ", "");
            }
            //
            for (int i = 0; i < decStrings.Count; i++)
            {
                FinishString += DecodeLine(decStrings[i], decCharsets[i], decEncodingTypes[i]);
            }
            return FinishString;
        }
        
        // Декодирует саму строку с задаными кодировками
        string DecodeLine(string encstring, string charset, string encodingType)
        {
            try
            {
                if (encodingType.ToLower() == "b")
                {
                    encstring = encstring.Replace(" ", "");
                    int modl = encstring.Length % 4;
                    if (modl > 0)
                        encstring = encstring.Remove(encstring.Length - modl);
                    byte[] encBytes = Convert.FromBase64String(encstring);
                    byte[] resBytes = Encoding.Convert(Encoding.GetEncoding(charset), Encoding.GetEncoding("windows-1251"),
                        encBytes, 0, encBytes.Length);
                    encstring = Encoding.GetEncoding("windows-1251").GetString(resBytes, 0, resBytes.Length);
                }
                else if (encodingType.ToLower() == "q")
                {
                    encstring = encstring.Replace(" ", "");
                    encstring = qpdecode(encstring, charset);
                    encstring = encstring.Replace("?=", "");
                }
                else
                {
                    byte[] encBytes = Encoding.GetEncoding(charset).GetBytes(encstring);
                    byte[] resBytes = Encoding.Convert(Encoding.GetEncoding(charset), Encoding.GetEncoding("windows-1251"),
                        encBytes, 0, encBytes.Length);
                    encstring = Encoding.GetEncoding("windows-1251").GetString(resBytes, 0, resBytes.Length);
                }
            }
            catch { }
            return encstring;
        }

        #region спизженый бред по декодированию "Q"
        string qpcharset = "";
        string qpdecode(string str,string mcharset)
        {
            string decodedString = "";
            qpcharset = mcharset;
            string value = str;
            Regex re = new Regex("(\\=([0-9A-F][0-9A-F]))",RegexOptions.IgnoreCase);
            decodedString += re.Replace(value, new MatchEvaluator(HexDecoderEvaluator));
            decodedString = decodedString.Replace('_', ' ');
            return decodedString;
        }
        private string HexDecoderEvaluator(Match m)
        {
            string hex = m.Groups[2].Value;
            int iHex = Convert.ToInt32(hex, 16);
            // Rerutn the string in the charset defined
            byte[] bytes = new byte[1];
            bytes[0] = Convert.ToByte(iHex);
            return Encoding.GetEncoding(qpcharset).GetString(bytes);
        }
        #endregion
    }
}